/********************************************************
 * Filename: TclScanner.java
 * Author: LMU
 * Program: TUnit
 * Description: Creates the tcl scanner for syntax 
 * highlighting, commenting, and strings.   
 * Revision History:
 * 20060426: Initial Revision.
 * *****************************************************/

package edu.lmu.cs.tUnit.editor;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.preference.PreferenceConverter;
import org.eclipse.jface.text.TextAttribute;
import org.eclipse.jface.text.rules.EndOfLineRule;
import org.eclipse.jface.text.rules.IRule;
import org.eclipse.jface.text.rules.IToken;
import org.eclipse.jface.text.rules.RuleBasedScanner;
import org.eclipse.jface.text.rules.SingleLineRule;
import org.eclipse.jface.text.rules.Token;
import org.eclipse.jface.text.rules.WhitespaceRule;
import org.eclipse.jface.text.rules.WordRule;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.widgets.Display;

import edu.lmu.cs.tUnit.plugin.TUnitPlugin;
import edu.lmu.cs.tUnit.preferences.TclPreferencesConstants;

public class TclScanner extends RuleBasedScanner {
	
	public static final String[] tclKeywords1 = {
		"after",
		"append",
		"array",
		"auto_execok",
		"auto_load",
		"auto_mkindex",
		"auto_reset",
		"bgerror",
		"binary",
		"break",
		"case",
		"catch",
		"cd",
		"clock",
		"close",
		"concat",
		"continue",
		"encoding",
		"eof",
		"error",
		"eval",
		"exec",
		"exit",
		"expr",
		"else",
		"elseif",
		"fblocked",
		"fconfigure",
		"fcopy",
		"file",
		"fileevent",
		"flush",
		"for",
		"foreach",
		"format",
		"gets",
		"glob",
		"global",
		"history",
		"if",
		"incr",
		"info",
		"interp",
		"join",
		"lappend",
		"lindex",
		"linsert",
		"list",
		"llength",
		"load",
		"lrange",
		"lreplace",
		"lsearch",
		"lset",
		"lsort",
		"namespace",
		"open",
		"package",
		"parray",
		"pid",
		"proc",
		"puts",
		"pwd",
		"read",
		"regexp",
		"registry",
		"regsub",
		"rename",
		"return",
		"scan",
		"seek",
		"set",
		"socket",
		"source",
		"split",
		"string",
		"subst",
		"switch",
		"tell",
		"time",
		"trace",
		"tcl_endOfWord",
		"tcl_startOfNextWord",
		"tcl_startOfPreviousWord",
		"tcl_wordBreakAfter",
		"tcl_wordBreakBefore",
		"unknown",
		"unset",
		"update",
		"uplevel",
		"upvar",
		"variable",
		"vwait",
		"while"
	};
	
	public static final String[] tclKeywords2 = {
		"auto_execs",
		"auto_index",
		"auto_noexec",
		"auto_noload",
		"auto_path",
		"env",
		"ErrorCode",
		"ErrorInfo",
		"errorInfo",
		"flatlist",
		"tcl_library",
		"tcl_patchLevel",
		"tcl_pkgPath",
		"tcl_platform",
		"tcl_precision",
		"tcl_rcFileName",
		"tcl_rcRsrcName",
		"tcl_version",
		"tcl_nonwordchars",
		"tcl_wordchars",
		"unknown_active",
		"bell",
		"bind",
		"bindtags",
		"bitmap",
		"button",
		"canvas",
		"checkbutton",
		"clipboard",
		"destroy",
		"entry",
		"event",
		"focus",
		"frame",
		"grab",
		"grid",
		"image",
		"label",
		"listbox",
		"lower",
		"menu",
		"menubutton",
		"message",
		"option",
		"pack",
		"photo",
		"place",
		"radiobutton",
		"raise",
		"scale",
		"scrollbar",
		"selection",
		"send",
		"text",
		"tk",
		"tk_bindForTraversal",
		"tk_bisque",
		"tk_chooseColor",
		"tk_dialog",
		"tk_focusFollowsMouse",
		"tk_focusNext",
		"tk_focusPrev",
		"tk_getOpenFile",
		"tk_getSaveFile",
		"tk_menuBar",
		"tk_messageBox",
		"tk_optionMenu",
		"tk_popup",
		"tk_setPalette",
		"tkerror",
		"tkvars",
		"tkwait",
		"toplevel",
		"winfo",
		"wm",
		"acos",
		"asin",
		"atan",
		"atan2",
		"ceil",
		"cos",
		"cosh",
		"exp",
		"floor",
		"fmod",
		"hypot",
		"log",
		"log10",
		"pow",
		"sin",
		"sinh",
		"sqrt",
		"tan",
		"tanh",
		"abs",
		"double",
		"int",
		"round",
		"rand",
		"srand",
		"wide"
	};
	
	/**
	 * Creates a Tcl code scanner
	 */
	public TclScanner() {
		super();
		setRules(createRules());
	}
	
	/**
	 * Create the rules for syntax highlighting
	 *
	 */
	public IRule[] createRules() {
		IPreferenceStore store = TUnitPlugin.getDefault().getPreferenceStore();
		Color cTCLKEYWORD1 = new Color(Display.getCurrent(), PreferenceConverter.getColor(store, TclPreferencesConstants.P_KEYWORDCOLOR1));
		Color cTCLKEYWORD2 = new Color(Display.getCurrent(), PreferenceConverter.getColor(store, TclPreferencesConstants.P_KEYWORDCOLOR2));
		Color cCOMMENT = new Color(Display.getCurrent(), PreferenceConverter.getColor(store, TclPreferencesConstants.P_COMMENTCOLOR));
		Color cDEFAULT = new Color(Display.getCurrent(), PreferenceConverter.getColor(store, TclPreferencesConstants.P_DEFAULTCOLOR));
		
		IToken tclKeyword1 = new Token(new TextAttribute(cTCLKEYWORD1, null, SWT.BOLD));
		IToken tclKeyword2 = new Token(new TextAttribute(cTCLKEYWORD2));
		IToken comment = new Token(new TextAttribute(cCOMMENT));
		IToken other = new Token(new TextAttribute(cDEFAULT));
		
		List rules = new ArrayList();
		
		// tricky rules
		rules.add(new SingleLineRule("upvar #", " ", tclKeyword1));
		rules.add(new SingleLineRule("\\", " ", other));
		
		// add rule for comments
		rules.add(new EndOfLineRule("#", comment));
		
		// add generic whitespace rule.
		rules.add(new WhitespaceRule(new TclWhitespaceDetector()));
				
		WordRule wordRule = new WordRule(new TclWordDetector(), other);
		
		// Add word rule for Tcl Keywords Set 1
		for(int i = 0; i < tclKeywords1.length; i++) {
			wordRule.addWord(tclKeywords1[i], tclKeyword1);
		}
		
		// Add word rule for Tcl Keywords Set 2
		for(int i = 0; i < tclKeywords2.length; i++) {
			wordRule.addWord(tclKeywords2[i], tclKeyword2);
		}
		
		rules.add(wordRule);
		
		setDefaultReturnToken(other);
		
		IRule[] result = new IRule[rules.size()];
		rules.toArray(result);
		return result;
		
	}
	
	/**
	 * updates the the coloring rules according the prefernces.
	 */
    public void updateColors() {
        setRules(createRules());
    }
}
